﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

namespace HuaXingSDK
{
    public class FromHXRequest
    {
        private Dictionary<Type, Delegate> _callbacks = new Dictionary<Type, Delegate>();
        private static Dictionary<string, Type> _codeToResType = new Dictionary<string, Type>();

        static FromHXRequest()
        {
            var types = typeof(FromHXRequest).Assembly.GetExportedTypes().Where(i => !i.IsAbstract && i.IsClass).
                ToArray();

            foreach (var t in types)
            {
                var attrs = t.GetCustomAttributes(typeof(FromHuaXingAttribute), true) as FromHuaXingAttribute[];
                if (attrs == null || attrs.Length < 1) continue;
                var attr = attrs[0];
                if (attr.TransCode == null || attr.TransCode.Length < 1) continue;
                foreach (var code in attr.TransCode)
                {
                    if (_codeToResType.ContainsKey(code.ToUpper()))
                        throw new ArgumentException($"{code}已被指定是{_codeToResType[code].Name}的TransCode。");
                    _codeToResType.Add(code.ToUpper(), t);
                }
            }
        }

        public void Process<T>(Action<T> callback) where T : HXFrom
        {
            var t = typeof(T);

            if (_callbacks.ContainsKey(t))
                throw new ArgumentException($"{t.Name}的处理程序已存在。");

            var attrs = t.GetCustomAttributes(typeof(FromHuaXingAttribute), true) as FromHuaXingAttribute[];

            if (attrs == null || attrs.Length < 1)
                throw new NotSupportedException($"{t.Name}没有标记{nameof(FromHuaXingAttribute)}。");

            _callbacks.Add(t, callback);
        }

        protected virtual Type GetResTypeByTransCode(string code)
        {
            code = code.ToUpper();
            if (_codeToResType.ContainsKey(code))
                return _codeToResType[code];
            return null;
        }

        public virtual void OnProcess(string message)
        {
            string text;
            if (Uilts.CheckSign(message, out text))
                throw new CheckSignException(message);
            
            var xml = new XmlDocument();
            xml.LoadXml(text);
            var root = xml.GetNodeByName("document");
            if (root == null)
                throw new HXException("没有找到Document节点。");
            var body = root.GetNodeByName("body");
            if (body == null)
                return;
            var codeNode = body.GetNodeByName("transCode");
            if (codeNode == null)
            {
                codeNode = root.GetNodeByName("header");

                if (codeNode != null)
                {
                    codeNode = codeNode.GetNodeByName("transCode");
                }
                if (codeNode == null)
                {
                    throw new HXException("没找到TransCode节点。");
                }
            }
            if (string.IsNullOrEmpty(codeNode.InnerText))
                throw new HXException("TransCode中没有内容。");

            var code = codeNode.InnerText.ToUpper();
            var resType = GetResTypeByTransCode(code);

            if (resType == null)
                throw new HXException($"未实现对应的{typeof(HXResponse).Name}:{code}");

            if (_callbacks.ContainsKey(resType) == false)
                throw new HXException($"没有注册{resType.Name}的处理委托。");

            var res = Activator.CreateInstance(resType, text);

            _callbacks[resType].DynamicInvoke(res);
        }
    }
}
